package org.ns.framework.datasource.database;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 事务管理引用关系.
 * 
 * @author zhangxingyu
 *
 */
public abstract class TransactionReference implements Transaction {
	private AtomicInteger referenceCount = new AtomicInteger();
	private Set<SegmentMode> segmentModes = new HashSet<SegmentMode>(); // 我的是否进行分割处理
	private final long id; // 线程ID
	
	/**
	 * 自动提交
	 */
	private Boolean autoCommit;
	private boolean defaultAutoCommit;

	protected TransactionReference() {
		id = Thread.currentThread().getId(); // 当前线程
	}

	protected Set<SegmentMode> getSegmentModes() {
		return segmentModes;
	}

	protected Set<SegmentMode> getChildSegmentMode() {
		if (segmentModes != null) {
			Set<SegmentMode> res = new HashSet<>();
			if (segmentModes.contains(SegmentMode.tempSegment)) {
				res.add(SegmentMode.segment); // 需要分割自己
			}
			if (segmentModes.contains(SegmentMode.segmentChild)) {
				res.add(SegmentMode.segment); // 需要分割自己
			}
			if (segmentModes.contains(SegmentMode.segmentChilds)) {
				res.add(SegmentMode.segment); // 需要分割自己
				res.add(SegmentMode.segmentChild); // 需要分割子事务管理.
				res.add(SegmentMode.segmentChilds); // 需要分割孙子事务管理.
			}
			return res;
		}
		return null;
	}

	protected void segment(SegmentMode... segmentModes) {
		if (this.segmentModes == null) {
			this.segmentModes = new HashSet<SegmentMode>();
		}
		if (segmentModes == null || segmentModes.length == 0) {
			this.segmentModes.add(SegmentMode.segment);
		} else {
			for (SegmentMode segmentMode : segmentModes) {
				this.segmentModes.add(segmentMode);
			}
		}
	}
	
	protected boolean existSegment(SegmentMode segmentMode) {
		return this.segmentModes != null && this.segmentModes.contains(SegmentMode.tempSegment); 
	}
	
	protected void unsegment(SegmentMode...segmentModes) {
		if (this.segmentModes != null) {
			for (SegmentMode segmentMode : segmentModes) {
				this.segmentModes.remove(segmentMode);
			}
		}
	}

	protected void setSegmentModes(Set<SegmentMode> segmentModes) {
		this.segmentModes = segmentModes;
	}

	/**
	 * 引用计数
	 * 
	 * @return
	 */
	protected int reference() {
		return referenceCount.incrementAndGet();
	}

	/**
	 * 释放引用计数
	 * 
	 * @return
	 */
	protected int release() {
		return referenceCount.accumulateAndGet(1, (prev, x) -> {
			if (prev == 0) {
				return 0;
			}
			return prev - x;
		});
	}

	public int getReference() {
		return referenceCount.get();
	}

	@Override
	public long getId() {
		return id;
	}
	
	protected void setDefaultAutoCommit(boolean defaultAutoCommit) {
		this.defaultAutoCommit = defaultAutoCommit;
	}
	
	public void setAutoCommit(Boolean autoCommit) {
		this.autoCommit = autoCommit;
	}
	public boolean isAutoCommit() {
		return autoCommit == null ? defaultAutoCommit : autoCommit;
	}
	
	public Boolean getAutoCommit() {
		return autoCommit;
	}
	
}
